package fiuba.algo3.XMLProcessor.EntradaSalida;


import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class LectorTokens
{
	public final boolean INCLUSIVE = true;
	public final boolean NOINCLUSIVE = false;
	
	BufferedReader buffReader;
	char ultimoCaracter;
	boolean hayChar;

	public LectorTokens(BufferedReader buffReader)
	{
		hayChar = false;
		this.buffReader = buffReader;
	}

	public LectorTokens(FileReader fileReader)
	{
		this(new BufferedReader(fileReader));
	}

	public LectorTokens(String nombreArchivo) throws FileNotFoundException
	{
		this(new FileReader(nombreArchivo));
	}

	public void cerrar()
	{
		try
		{
			this.buffReader.close();
		}
		catch (IOException ex)
		{
			Logger.getLogger(LectorTokens.class.getName()).log(Level.SEVERE, "LectorTokens: No se pudo cerrar el BufferedReader", ex);
		}
	}

	private char proximoCaracter()
	{
		if (!hayChar)
			try
			{
				return (char)buffReader.read();
			}
			catch (IOException ex)
			{
				return 0;
			}

		hayChar = false;
		return ultimoCaracter;
	}

	private void devolverCaracter(char a)
	{
		this.ultimoCaracter = a;
		this.hayChar = true;
	}

	public void saltearEspacios()
	{
		char a = proximoCaracter();
		while(Character.isWhitespace(a))
			a = proximoCaracter();

		devolverCaracter(a);
	}

	public void saltearHasta(char token, boolean inclusive)
	{
		char a = proximoCaracter();
		while(a != token)
			a = proximoCaracter();

		if (!inclusive)
			devolverCaracter(a);
		else
			this.hayChar = false;
	}

	private char buffer[];
	private int tamanio = 128;

	private void resetearBuffer()
	{
		tamanio = 128;
		buffer = new char[tamanio];
	}

	private void redimensionarBuffer()
	{
		char bufferTemp[] = new char[tamanio*2];

		System.arraycopy(buffer, 0, bufferTemp, 0, tamanio);

		buffer = bufferTemp;
		tamanio *= 2;
	}

	private boolean esValido(char a)
	{
		return Character.isUnicodeIdentifierPart(a);
	}

	public String leerIdentificador()
	{
		resetearBuffer();
		int ultimo = 0;
		char a = proximoCaracter();
		while(esValido(a))
			{
				buffer[ultimo++] = a;
				//redimension
				if (tamanio == ultimo)
					redimensionarBuffer();
				a = proximoCaracter();
			}

		devolverCaracter(a);

		return String.copyValueOf(buffer, 0, ultimo);
	}

	public String leerHasta(char token, boolean inclusive)
	{
		resetearBuffer();
		int ultimo = 0;
		char a = proximoCaracter();
		while(a != token)
			{
				buffer[ultimo++] = a;
				//redimension
				if (tamanio == ultimo)
					redimensionarBuffer();
				a = proximoCaracter();
			}

		if (!inclusive)
			devolverCaracter(a);
		else
			{
				buffer[ultimo++] = a;
				this.hayChar = false;
			}

		return String.copyValueOf(buffer, 0, ultimo);		
	}

	public String leerContenidoEntreTokens(char tokenInicio, char tokenFinal, boolean inclusive)
	{
		saltearHasta(tokenInicio,!inclusive);
		return leerHasta(tokenFinal,inclusive);
	}

	//Valido si en algun momento anterior al llamado se devolvio un caracter
	public char verUltimoCaracter()
	{
		return ultimoCaracter;
	}
}
